/**************************************************************************
 *
 * Copyright (c) 2015-2017  QIKU Company             　　　　　　　            
 *                 奇酷软件（深圳）有限公司  版权所有 2015-2017
 *
 * PROPRIETARY RIGHTS of QIKU Company are involved in the  　　　　　　     
 * subject matter of this material.  All manufacturing, reproduction, use, 
 * and sales rights pertaining to this subject matter are governed by the  
 * license agreement.  The recipient of this software implicitly accepts   
 * the terms of the license.                                               
 * 本软件文档资料是奇酷公司的资产,任何人士阅读和使用本资料必须获得                     
 * 相应的书面授权,承担保密责任和接受相应的法律约束.                                 
 *
 **************************************************************************/
package com.yw.android.common.utils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * 捕获异常的执行类
 *
 * @author yuanwei
 */
public abstract class Threadable implements Runnable {


    /**
     * 该执行对象名称
     */
    private final String name;

    /**
     * 构造函数
     */
    public Threadable() {
        this("Threadable", false);
    }

    /**
     * 构造函数
     *
     * @param name 该执行对象名称
     */
    public Threadable(String name) {
        this(name, false);
    }

    /**
     * 构造函数
     *
     * @param name               该执行对象名称
     * @param threadNameAppended 是否追加线程的对象名
     */
    public Threadable(String name, boolean threadNameAppended) {
        this.name = (threadNameAppended ? (name + "@" + Thread.currentThread().getName()) : name);
    }

    /**
     * 获取该执行对象名称
     *
     * @return 该执行对象名称
     */
    public String getName() {
        return name;
    }

    /**
     * 执行当前对象
     */
    public final void execute() {
        new Thread(this).start();
    }

    /**
     * 使用线程执行器执行当前对象
     *
     * @param executor 线程执行器
     */
    public final void execute(ExecutorService executor) {
        try {
            if (null == executor) {
                LOG.e("[" + name + "] execute failed(uninitialized)");
            } else if (executor.isShutdown() || executor.isTerminated()) {
                LOG.e("[" + name + "][" + executor
                        + "] execute failed(shutdowned)");
            } else {
                executor.execute(this);
            }
        } catch (Throwable t) {
            LOG.e("[" + name + "][" + executor
                    + "] execute failed(" + t.getClass().getSimpleName()
                    + "): " + t.getMessage());
        }
    }

    /**
     * 使用线程执行器执行当前对象
     *
     * @param executor 线程执行器
     * @param delays   延迟执行的时间，单位秒
     */
    public final void schedule(ScheduledExecutorService executor, long delays) {
        try {
            if (null == executor) {
                LOG.e("[" + name + "] schedule failed(uninitialized)");
            } else if (executor.isShutdown() || executor.isTerminated()) {
                LOG.e("[" + name + "][" + executor.hashCode()
                        + "] schedule failed(shutdowned)");
            } else {
                executor.schedule(this, delays, TimeUnit.SECONDS);
            }
        } catch (Throwable t) {
            LOG.e("[" + name + "][" + executor
                    + "] schedule failed(" + t.getClass().getSimpleName()
                    + "): " + t.getMessage());
        }
    }

    @Override
    public final void run() {
        // 设置线程名称，并保留之前的线程名称
        String preThreadName = setThreadName(name);

        try {
            if (!preFire()) {
                LOG.i("[" + name + "] run canceled");
            } else {
                doFire();
            }
        } catch (Throwable e) {
            LOG.e("[" + name + "] run failed(Throwable)", e);
        } finally {
            postFire();
            setThreadName(preThreadName);
        }
    }

    @Override
    public String toString() {
        return "Threadable(" + name + ")";
    }

    /**
     * 设置线程名称
     *
     * @param tName 指定的线程名称
     * @return 设置之前的线程名称
     */
    private String setThreadName(String tName) {
        String preThreadName = Thread.currentThread().getName();
        Thread.currentThread().setName(tName);
        return preThreadName;
    }

    /**
     * 主执行执行前准备过程
     *
     * @return true 继续执行；false 取消执行
     */
    protected boolean preFire() {
        return true;
    }

    /**
     * 主执行对象，需要重载，执行过程中抛出的任何异常都会被捕获
     */
    protected abstract void doFire();

    /**
     * 主执行执行结束后的过程，无论出现何种异常，都会执行到
     */
    protected void postFire() {
        // nothing to do default
    }
}
